#ifndef _PROPERTY_EX_H__
#define _PROPERTY_EX_H__

#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/advprops.h>

#include <AtlasBase.h>
#include <AtlasCommon.h>
#include "RefSelDlg.h"


struct PropClientData
{
	_U8 type;
	_U32 flags;
};

void ModifyValue(wxPGProperty* pg, wxVariant value);

template<class T, class BASE>
class CPropertyEx : public BASE
{
public:
	CPropertyEx(void* addr, _U8 type, const wxString& label, const wxString& name, T value)
		: BASE(label, name, value)
	{
		m_value = value;
		m_addr = addr;
		m_type = type;
		m_flags = 0x00;
	}

	virtual ~CPropertyEx()
	{
		PropClientData* pData = (PropClientData*)this->GetClientData();
		if(pData)
		{
			ATLAS_FREE(pData);
		}
	}

	void ModifyValue(const char* szValue)
	{	
		m_value = (char*)szValue;
		if(m_type == DDLReflect::TYPE_UUID)
		{
			A_UUID uuid;
			AUuidFromString(szValue, uuid);		
			memset(m_addr, 0, sizeof(A_UUID));
			memcpy(m_addr, &uuid, sizeof(A_UUID));
		}
		else if(m_type == DDLReflect::TYPE_ARRAY)
		{
			_U32 size = 0;
			wxString strSize = szValue;
			strSize.ToULong(&size);
			*((_U32*)m_addr) = size;
		}
		else
		{
			memset(m_addr, 0, sizeof(m_value));
			memcpy(m_addr, szValue, strlen(szValue));
		}
	}

	void ModifyValue(T value)
	{
		switch(m_type)
		{
		case DDLReflect::TYPE_U8:		
		case DDLReflect::TYPE_U16:	
		case DDLReflect::TYPE_U32:	
		case DDLReflect::TYPE_U64:	
			{
				m_value = value;
				*((T*)m_addr) = value;
			}
			break;
		case DDLReflect::TYPE_S8:
			{
				
			}
			break;
		case DDLReflect::TYPE_S16:
			{

			}
			break;
		case DDLReflect::TYPE_S32:	
			{
			
			}
			break;
		case DDLReflect::TYPE_S64:
			{
			
			}
			break;
		case DDLReflect::TYPE_F32:	
			{
				m_value = value;
				_F32* pAddr = (_F32*)m_addr;
				*pAddr = m_value;
			}
			break;
		case DDLReflect::TYPE_F64:
			{
				m_value = value;
				_F64* pAddr = (_F64*)m_addr;
				*pAddr = m_value;
			}
			break;
		case DDLReflect::TYPE_ARRAY:
			{
				assert(0);
			}
			break;
		case DDLReflect::TYPE_UUID:
		case DDLReflect::TYPE_STRING:
		case DDLReflect::TYPE_STRUCT:
		case DDLReflect::TYPE_MASK:
			{
				assert(0);
			}
			break;
		default:
			{
				assert(0);
			}
			break;
		}
	}

	void RereshSizeInfo(_U32 size)
	{
		char szInfo[10];
		sprintf(szInfo, "%d", size);
		SetValueFromString(szInfo);
	}

private:
	void* m_addr;
	_U8 m_type;
	T m_value;
	_U32 m_flags;
};

template<class T>
class CPropertyEx<T, wxLongStringProperty> : public wxLongStringProperty
{
public:
	CPropertyEx(void* addr, _U8 type, const wxString& label, const wxString& name, T value)
		: wxLongStringProperty(label, name, value)
	{
		m_value = value;
		m_addr = addr;
		m_type = type;
		
		A_UUID uuid;
		AUuidFromString(value, uuid);	

		SetInfoFromUUID(uuid);
	}

	virtual ~CPropertyEx() {}

	void SetInfoFromUUID(A_UUID& uuid)
	{
		const A_CONTENT_OBJECT* object = Atlas::ContentObject::Query(uuid);
		if(!object)
		{
			return;
		}

		wxString strValue = object->name._Value;
		strValue += ": ";
		strValue += m_value;

		this->SetValueFromString(strValue);
	}


	void ModifyValue(const char* szValue)
	{	
		m_value = (char*)szValue;
		if(m_type == DDLReflect::TYPE_UUID)
		{
			A_UUID uuid;
			AUuidFromString(szValue, uuid);		
			memset(m_addr, 0, sizeof(A_UUID));
			memcpy(m_addr, &uuid, sizeof(A_UUID));
		}
		else if(m_type == DDLReflect::TYPE_ARRAY)
		{
			_U32 size = 0;
			wxString strSize = szValue;
			strSize.ToULong(&size);
			*((_U32*)m_addr) = size;
		}
		else
		{
			memset(m_addr, 0, sizeof(m_value));
			memcpy(m_addr, szValue, strlen(szValue));
		}
	}

	void ModifyValue(T value)
	{
		switch(m_type)
		{
		case DDLReflect::TYPE_U8:		
		case DDLReflect::TYPE_U16:	
		case DDLReflect::TYPE_U32:	
		case DDLReflect::TYPE_U64:	
			{
				m_value = value;
				*((T*)m_addr) = value;
			}
			break;
		case DDLReflect::TYPE_S8:
		case DDLReflect::TYPE_S16:
		case DDLReflect::TYPE_S32:	
		case DDLReflect::TYPE_S64:
			{
				assert(0);
			}
			break;
		case DDLReflect::TYPE_F32:	
			{
				m_value = value;
				_F32* pAddr = (_F32*)m_addr;
				*pAddr = m_value;
			}
			break;
		case DDLReflect::TYPE_F64:
			{
				m_value = value;
				_F64* pAddr = (_F64*)m_addr;
				*pAddr = m_value;
			}
			break;
		case DDLReflect::TYPE_ARRAY:
			{
				assert(0);
			}
			break;
		case DDLReflect::TYPE_UUID:
		case DDLReflect::TYPE_STRING:
		case DDLReflect::TYPE_STRUCT:
		case DDLReflect::TYPE_MASK:
			{
				assert(0);
			}
			break;
		default:
			{
				assert(0);
			}
			break;
		}
	}

	void RereshSizeInfo(_U32 size)
	{
		char szInfo[10];
		sprintf(szInfo, "%d", size);
		SetValueFromString(szInfo);
	}

	virtual bool OnButtonClick(wxPropertyGrid* propGrid, wxString& strValue)
	{
		CRefSelDlg dlg(propGrid, m_strRefType);
		if(dlg.ShowModal() == wxID_OK)
		{
			wxString strSel = dlg.GetSelect();
			if(m_type == DDLReflect::TYPE_UUID_REF)
			{
				A_UUID uuid;
				AUuidFromString(strSel.c_str(), uuid);		
				memset(m_addr, 0, sizeof(A_UUID));
				memcpy(m_addr, &uuid, sizeof(A_UUID));
				m_value = strSel;
				//const A_CONTENT_OBJECT* object = Atlas::ContentObject::Query(uuid);

				//wxString strValue = object->name._Value;
				//strValue += ": ";
				//strValue += strSel;

				//this->SetValueFromString(strValue);

				SetInfoFromUUID(uuid);
				CStructEditView* pParentView = (CStructEditView*)propGrid->GetParent();
				pParentView->FlashView();
			}
		}
		return true;
	}

	void SetRefType(const char* ref_type)
	{
		m_strRefType = ref_type;
	}

private:
	void* m_addr;
	_U8 m_type;
	T m_value;
	wxString m_strRefType;
	_U32 m_flags;
};

#endif //_PROPERTY_EX_H__